/*
 * Copyright 2014 by État de Genève (Switzerland)
 * All rights reserved.
 *
 * Author: ELCA Informatique SA
 */
define(['services/dataservice', 
        'services/notifier', 
        'services/api', 
        'i18n', 
        'q', 
        'lists/listTemplatesDef'],
    function (ds, notifier, api, i18n, Q, listTemplatesDef) {

        // list types in java can be found in the file:
        // trunk\opus-shared\src\main\java\ch\ge\opus\shared\description\SearchId.java

        /**
         * List values (e.g. countries)
         * WARNING: these lists will be retrieved from the API eventually and not hardcoded (/initData call)
         * Please do not define lists here unless for development purpose!
         */
        var _valuesCache = {
        };

        /**
         * form views for entities
         */
        var _entityFormTemplates = {
            'PersonneMorale':       'tiers/personneMorale',
            'Communaute':           'tiers/communaute',
            'PersonnePhysique':     'tiers/personnePhysique',

            //TODO: when entity kind coming from the API is correct, define all correct available kinds here and delete others
            'PoursuiteOrdinaire':   'poursuites/poursuiteOrdinaire',
            'PoursuiteEntity':      'poursuites/poursuiteOrdinaire',
            'Poursuite':            'poursuites/poursuiteOrdinaire',

            'Requisition':          'requisitions/requisitionStandard'
        };


        /** Cache for each type definition
        */
        var _typeDefCache = {};

        /**
         * appConfig definition
         */
        return {
            // return default sort on a list
            getDefaultListSort: getListDefaultSort,
            // return column definition for a list type
            getColumns: getColumns,
            // get advanced search fields for a list type
            getSearchFields: getSearchFields,
            // get default filter fields for a list type
            getFilterFields: getFilterFields,
            // retrieve config and user from server, and cache list values
            loadConfigAndUser: loadConfigDataAndUser,
            // get a value list (like the countries)
            getValues: getValues,
            // get a label for a value (key) in the value lists
            getValueLabel: getValueLabel,
            getValueForKey: getValueForKey,

            // get templates configuration for list types
            getListTemplates: getlistTemplates,
            // get templates configuration for form type
            getFormForType: getEntityTemplate
        };

        /***********************************************************************************************/
        /** FUNCTION DEFINITIONS */

        /**
         * search in column definition for list type if a default order is specified,
         * otherwise returns an arbitrary default order
         */
        function getListDefaultSort(listType) {

            return getFromCache(listType).then(function (typeDef) {

                var sortBy = _.find(typeDef.columns, function (col) {
                    return typeof col.defaultOrder !== 'undefined';
                });

                if (sortBy) {
                    return {
                        dir: sortBy.defaultOrder,
                        id: sortBy.id
                    };
                } else {
                    return {
                        dir: 'ASC',
                        id: typeDef.columns[0].id
                    };
                }
            });
        }

        /**
         * Return the list of advanced fields for the demanded list type
         */
        function getSearchFields(listType) {
            return getFromCache(listType).then(function (typeDef) {

                var fieldsObj = {};
                _.each(typeDef.advancedSearchFields, function (fieldDef) {
                    fieldsObj[fieldDef.field] = null;
                });
                return fieldsObj;
            });
        }

        /**
         * Return the list of filter fields for the demanded list type
         */
        function getFilterFields(listType) {
            return getFromCache(listType).then(function (typeDef) {

                var fieldsObj = {};
                _.each(typeDef.defaultFilters, function (fieldDef) {
                    fieldsObj[fieldDef.field] = null;
                });
                return fieldsObj;
            });
        }


        /**
         * Get column definitions from Cache (or from server if not yet cached)
         */
        function getColumns(type, extended) {

            return getFromCache(type).then(function (typeDef) {
                return typeDef.columns;
            });
        }

        /**
         * Get which form template is configured for the entity type
         */
        function getEntityTemplate(entityType) {
            return _entityFormTemplates[entityType];
        }

        /**
         * get the various templates configured for each list type (list and table template, advanced search template, actions, etc....)
         */
        function getlistTemplates(listType) {
            if (!listTemplatesDef[listType]) {
                // invalid config
                var e = new Error(i18n.ts('cms:error.viewNotFound', listType));
                e.code = 404;
                throw e;
            } else {
                if(listTemplatesDef[listType].sameAs) {
                    return listTemplatesDef[listTemplatesDef[listType].sameAs];
                }
                return listTemplatesDef[listType];
            }
        }

        /**
         * get the value list identified by the listId (e.g. 'pays')
         */
        function getValues(listId) {
            return _valuesCache[listId];
        }

        /**
         * find a key value in a specific value list, and return its label
         */
        function getValueLabel(listId, key) {

            return getValueForKey(listId, key) || key;
        }

        /**
         * Return a key/label pair for a given key, or null if it doesn't exist
         */
        function getValueForKey(listId, key) {
            if(_valuesCache[listId]) {

                var keyValuePair = _.findWhere(_valuesCache[listId], { key: key });

                if(keyValuePair) {
                    return keyValuePair;
                }
            }

            return null;
        }

        /**
         * Initial loading of data (like user, value lists, locale...)
         */
        function loadConfigDataAndUser() {
            return ds.loadConfigData()
                .then(function (configData) {

                    // cache all value list
                    _.extend(_valuesCache, configData.lists);
                    // add a 'keyStr' prop for each k/v object, so the the
                    // <select> can be directly bound (it needs a string as key!)
                    /*_.each(_valuesCache, function(valueList) {
                        _.each(valueList, function(keyValue) {
                            keyValue.keyStr = keyValue.key + '';
                        });
                    });*/

                    return configData;
                })
                .fail(function (err) {
                    notifier.error(err);
                });
        }

        /**
         * Refresh the cache for the given type, and call a callback function once it's done
         */
        function refresh(type) {

            return api.getJsonFile('listTypeDef.json')
                .then(function (resultTypeDef) {
                    _.extend(_typeDefCache, resultTypeDef);
                    _typeDefCache._updateTs = new Date().getTime();

                    processColumns();
                    return _typeDefCache[type];
                });
        }

        /**
         * transform column headers with i18n, and add an index to each column for easier reference later
         */
        function processColumns() {

            _.each(_typeDefCache, function(typeDef) {

                if (typeDef && typeDef.columns) {
                    _.each(typeDef.columns, function (col, index) {
                        // i18nize column headers once for all
                        if (col.header) {
                            col.header = i18n.t(col.header);
                        }
                        if (col.shortHeader) {
                            col.shortHeader = i18n.t(col.shortHeader);
                        }

                        // setup columns' indexes for later use
                        col.index = index;
                    });
                }
            });
        }

        /**
         * Choose whether to get data from cache or to refresh data from server.
         */
        function getFromCache(type) {

            if (_typeDefCache[type]) {
                if(_typeDefCache[type].sameAs) {
                    var alias = _typeDefCache[type].sameAs;
                    return Q(_typeDefCache[alias]);
                } else {
                    return Q(_typeDefCache[type]);
                }
            } else {
                return refresh(type).then(function(typeDef) {

                    if(typeDef.sameAs) {
                        return _typeDefCache[typeDef.sameAs];
                    } else {
                        return typeDef;
                    }
                });
            }
        }

    });
